#pragma once 

#include<iostream>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<pthread.h>
#include<unistd.h>

#define NUM 32 

template<class T>
class BlockQueue
{
   private:

    bool IsFull()
    {
      return q.size()==cap;
    }

    bool IsEmpty()
    {
      return q.empty();
    }

  public:

    BlockQueue(int _cap=NUM)
      :cap(_cap)
    {
      pthread_mutex_init(&lock,nullptr);
      pthread_cond_init(&full,nullptr);
      pthread_cond_init(&empty,nullptr);
    }

    void Push(const T& in)
    {
      pthread_mutex_lock(&lock);
      while(IsFull())
      {
        //不能进行生产，需要进行等待，等待q可以容纳新的数据。
        pthread_cond_wait(&full,&lock);//在特定条件变量下等待，进入等待时自动释放互斥锁,等待完成被唤醒时，又会自动获取锁
      }
      q.push(in);
      if(q.size()>=cap/2)
      {
        std::cout<<"数据量充足，可以消费"<<std::endl;
        pthread_cond_signal(&empty);
      }
      pthread_mutex_unlock(&lock);
    }

    void Pop(T& out)
    {
      pthread_mutex_lock(&lock);
      while(IsEmpty())
      {
        //不能进行消费，需要等待，等待q有新数据的时候
        pthread_cond_wait(&empty,&lock);
      }
      out=q.front();
      q.pop();
      if(q.size()<=cap/2)
      {
        std::cout<<"数据量过低，开始补充生产"<<std::endl;
        pthread_cond_signal(&full);
      }
      pthread_mutex_unlock(&lock);
    }

    ~BlockQueue()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&full);
      pthread_cond_destroy(&empty);
    }

  private:

    std::queue<T> q;//临界资源
    int cap;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;
};
